
#ifndef TOKZRGENTR_GEN_TOKENIZER_DATAS_H
#define TOKZRGENTR_GEN_TOKENIZER_DATAS_H
#include"asserts.h"
#include"automatics.h"
#include"char_set_table.h"
#include"automatics_test.h"
#include"regex_parser_test.h"
namespace TokzrGentr
{
	//#	connected_table[status_index][value_index] access api should be provided.
	//#	mark connected_table.get_mark(status_index) api should be provided.
	class connected_table
	{
	public:
		static connected_table *parse_from(const dfa &target);
	private:
		class access_proxy
		{
		private:
			unsigned *_row;
			unsigned _len;
		public:
			access_proxy(unsigned *row,unsigned len)
				:_row(row), _len(len) {}
			unsigned &operator[](size_t index) const
			{
				ASSERT_MSG(index < _len,"ERROR:OUT OF RANGE.");
				return _row[index];
			}
			unsigned *begin() const
			{
				return _row;
			}
			unsigned *end() const
			{
				return _row + _len;
			}
		};
	private:
		unsigned **_matrix;
		unsigned _status_num;
		unsigned _value_num;
		unsigned *_status_marks;
		connected_table()
			:_status_num(0),_value_num(0),_matrix(nullptr){
		}
		connected_table(unsigned s_num, unsigned v_num)
		{
			_status_num = s_num;
			_value_num = v_num;
			_status_marks = new unsigned[_status_num];
			_matrix = new unsigned*[_status_num];
			for (unsigned i = 0; i < _status_num; i++)
			{
				_matrix[i] = new unsigned[_value_num];
				for (unsigned j = 0; j < _value_num; j++)
					_matrix[i][j] = _status_num;
			}
		}
	public:
		unsigned status_num() const
		{
			return _status_num;
		}
		unsigned value_num() const
		{
			return _value_num;
		}
		unsigned get_mark(unsigned status_index) const
		{
			ASSERT_MSG(status_index <= _status_num,"ERROR:OUT OF RANGE.");
			return _status_marks[status_index];
		}
		inline unsigned start_status() const
		{
			return 0;
		}
		access_proxy operator[](size_t index) {
			ASSERT_MSG(index < _status_num, "ERROR:OUT OF RANGE.");
			return access_proxy(_matrix[index], _value_num);
		}
		~connected_table()
		{
			if (_matrix)
			{
				for (unsigned i = 0; i < _status_num; i++)
					delete [] _matrix[i];
				delete [] _matrix;
			}

			if (_status_marks)
				delete[] _status_marks;
		}
	};

	connected_table* connected_table::parse_from(const dfa &target)
	{
		//#traverse the dfa graph to search infomation
		std::map<dfa_status*,unsigned> status_traversed_with_marks;
		std::vector<dfa_status*> status_waiting_traverse;
		status_waiting_traverse.push_back(target.start());
		unsigned max_value = 0;
		while (!status_waiting_traverse.empty())
		{
			auto s = status_waiting_traverse.back();
			status_waiting_traverse.pop_back();
			if (status_traversed_with_marks.find(s)
				!= status_traversed_with_marks.end())
				continue;
			auto no_ = static_cast<unsigned>(status_traversed_with_marks.size());
			status_traversed_with_marks.insert({ s,no_ });
			for (auto trans : *s)
			{
				status_waiting_traverse.push_back(trans->to());
				if (trans->value() > max_value)
					max_value = trans->value();
			}
		}

		connected_table *table = new connected_table(
			status_traversed_with_marks.size(),
			max_value + 1
		);

		//# Construct the connected table
		for (auto p : status_traversed_with_marks)
		{
			table->_status_marks[p.second] = p.first->mark();
			for (auto trans : *(p.first))
				table->_matrix[p.second][trans->value()] = status_traversed_with_marks[trans->to()];
		}

		return table;
	}
}
#endif // !TOKZRGENTR_GEN_TOKENIZER_DATAS_H
